/***************************************************************************
 *   Copyright (C) 2008 by Goliash   *
 *   goliash@goliash.net   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

 #include "scan_dialog.h"



 #include "fcntl.h"
 #include <stdio.h>
 #include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/fs.h>
#include <string.h>

#include <iostream>
#include <streambuf>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

ScanDialog::ScanDialog(QWidget *parent, Medium *medium) : QDialog(parent)
{
	setupUi(this);
	this->medium = medium;
	mw = parent;
	//state_label->setText("--- loading ---");
	//connect(refreshButton, SIGNAL(clicked()), this, SLOT(refresh()));
	connect(this, SIGNAL(valueChanged(int)), progressBar, SLOT(setValue(int)));
	//connect(this, SIGNAL(valueChanged(...)), listWidget, SLOT(scrollToItem(...));
	prefs = Preferences::instance();
}

void ScanDialog::scanMedium()
{
	// projdu rekurzivne vsechny soubory/adresare na zaklade mounted path
	// u kazdeho souboru	ulozim: jmeno, rodic, typ, in-root, medium-id
	//					vypisu: jmeno (celou cestu)
	// nutno spoustet pres vlakno
        QString fileName;
	int count = 0;
	QDirIterator it(medium->getPath(), QDirIterator::Subdirectories);
	while (it.hasNext()) {
		// just counting
		it.next();
		count++;
	}
	progressBar->setMaximum(count);
	count = 0;

	QTime time;
	time.start();

	QDirIterator iter(medium->getPath(), QDirIterator::Subdirectories);
	while (iter.hasNext()) {
		count++;
		//progressBar->setValue(count);
		emit valueChanged(count);
		iter.next();
		if(iter.fileName().compare("..") && !iter.filePath().endsWith("/.")) {
			// adding new item to listWidget: filePath without medium path
			fileName = iter.filePath().right(iter.filePath().length() - medium->getPath().length() - 1);
			new QListWidgetItem(fileName, this->listWidget);
			
			// creating of new objects according to filesystem
			//(medium->children).insert((medium->children).size(), new File(fileName));
			QList<File *> *currentFolder = &(medium->children);
			//currentFolder->insert(currentFolder->size(), new File(fileName));
			
			QStringList list = fileName.split("/");
			for(int i = 0; i<list.size(); i++) {
				//if(fileName == "disk") qDebug() << "huuu---------------";
				//qDebug() << fileName;
				// check if exists
				bool fileNotFound = true;
				for(int j = 0; j<currentFolder->size(); j++) {
					if(currentFolder->at(j)->getName() == list[i]) {
						fileNotFound = false;
						currentFolder = &(currentFolder->at(j)->children);
						break;
					}
				}
				// not exists, creating new one
				if(fileNotFound) {
					currentFolder->append(new File(list[i]));
					int index = currentFolder->size()-1;
					if(i<list.size()-1) {
						currentFolder->at(index)->setFolder(true);
						
						// probably bug in QDirIterator, folder ".disk" is not iterated
						if(currentFolder->at(index)->getSize() == -1) {
							currentFolder->at(index)->setSize(2048);
						}
					}
					else {
						// now check the file and set values
						QFileInfo fileInfo = iter.fileInfo();
						currentFolder->at(index)->setFolder(fileInfo.isDir());
						currentFolder->at(index)->setRights(fileInfo.isReadable(), fileInfo.isWritable(), fileInfo.isExecutable());
						currentFolder->at(index)->setOwners(fileInfo.owner(), fileInfo.group());
						currentFolder->at(index)->setDates(fileInfo.created(), fileInfo.lastModified());
						currentFolder->at(index)->setSize(fileInfo.size());
						
						//iter.filePath()
						// if it is an image, do file scanning
						if( fileInfo.suffix() == "jpg" || fileInfo.suffix() == "JPG" ) {
							currentFolder->at(index)->setType(File::JPEG);
							if( prefs->filter_JPEG ) {
								processFilterJPEG(iter.filePath(), currentFolder->at(index));
							}
							//else 
							//	currentFolder->at(index)->getPicture()->setExif("0");
							// not necessary, Picture is NULL, so there will be no item in Pictures table in sqlite
						}
						if( fileInfo.suffix() == "mp3" || fileInfo.suffix() == "MP3" ) {
							currentFolder->at(index)->setType(File::AudioContent);
							if( prefs->filter_mp3 ) {
								processFilterMp3(iter.filePath(), currentFolder->at(index));
							}
						}
						if( fileInfo.suffix().toLower() == "txt" || fileInfo.suffix().toLower() == "nfo" ) {
							currentFolder->at(index)->setType(File::Text);
							if( prefs->filter_txt ) {
								processFilterTxt(iter.filePath(), currentFolder->at(index), fileInfo.suffix().toLower());
							}
						}
						if( fileInfo.suffix().toLower() == "pdf" ) {
							currentFolder->at(index)->setType(File::PDF);
							if( prefs->filter_pdf ) {
								processFilterPdf(iter.filePath(), currentFolder->at(index));
							}
						}
					}
					currentFolder = &(currentFolder->at(index)->children);
				}
			}
		}
		else
			qDebug() << "vynechavam" <<iter.fileName();
	}
	//qDebug() << medium->childrenToString();
	//qDebug() << count;

	medium->setExploringTime(time.elapsed()/1000);

	// adds created structure into db
	saveIntoDB();
}

void ScanDialog::saveIntoDB()
{
	// going through lists in File and calling QSqlQuery
	
	// begin transaction?
	QSqlDatabase db = ((MainWindow *)mw)->getDb();
     bool ok = db.open();
	if(ok) {
		db.transaction();
		QSqlQuery query;
		query.prepare("INSERT INTO media (name, orig_name, size, filesystem, added_to_db, size_in_db, comment, exploring_time, create_application, creation_time) VALUES (:name, :orig_name, :size, :filesystem, :added_to_db, :size_in_db, :comment, :exploring_time, :create_application, :creation_time)");
		query.bindValue(":name", medium->getName());
		query.bindValue(":orig_name", medium->getOriginal_name());
		query.bindValue(":size", medium->getSize());
		query.bindValue(":filesystem", medium->getFilesystem());
		query.bindValue(":added_to_db", QDateTime::currentDateTime().toString("yyyyMMddhhmmss"));
		query.bindValue(":size_in_db", 0);
		query.bindValue(":comment", "");
		query.bindValue(":exploring_time", medium->getExploringTime());
		query.bindValue(":create_application", medium->getCreateApplication());
		query.bindValue(":creation_time", medium->getCreation_time());
		query.exec();
		query.finish();

		// existuje query.lastInsertId(), opravit pozdeji
		query.prepare("SELECT id FROM media WHERE id=last_insert_rowid()");
		query.exec();
		if(query.next()) {
			medium->setId(query.value(0).toInt());
			qDebug() << medium->getId();
		}

		insertFileListToSql(medium->children, 1, 0, db);
		
		query.finish();
		qDebug() << db.commit();
		qDebug() << db.lastError().text();
		free(medium);
	}
	// end of transaction?
}

void ScanDialog::insertFileListToSql(QList<File *> list, int in_root, int parent_id, QSqlDatabase db)
{
	// pokud je this medium, tak soubory jsou in_root, parent_id=0
	// jinak in_root=0, parent_id=file
	
	QSqlQuery query;
	int type;
	int parent = 0;
	if(!list.isEmpty()) {
		for(int i=0; i<list.size(); i++) {
			//qDebug() << "inserting file (sql in future)" << list[i]->getName();
			query.prepare("INSERT INTO files (name, parent_id, id_type, in_root, id_medium) VALUES (:name, :parent_id, :id_type, :in_root, :id_medium)");
			query.bindValue(":name", list[i]->getName());
			query.bindValue(":parent_id", parent_id);

			query.bindValue(":in_root", in_root);
			query.bindValue(":id_medium", medium->getId());
			
			// file type
			if(list[i]->isFolder())
				type = File::Folder;
			else if(list[i]->getType()==File::JPEG)
				type = File::JPEG;
			else if(list[i]->getType()==File::AudioContent)
				type = File::AudioContent;
			else if(list[i]->getType()==File::Text)
				type = File::Text;
			else if(list[i]->getType()==File::PDF)
				type = File::PDF;
			else
				type = File::Unknown;

			query.bindValue(":id_type", type);
			query.exec();
			query.finish();
			
			query.prepare("SELECT id FROM files WHERE id=last_insert_rowid()");
			query.exec();
			if(query.next()) {
				parent = query.value(0).toInt();

				query.prepare("INSERT INTO general (id, size, creation_date, rights, last_change) VALUES (:id, :size, :creation_date, :rights, :last_change)");
				query.bindValue(":id", parent);
				query.bindValue(":size", list[i]->getSize());
				query.bindValue(":creation_date", list[i]->getCreatedDate().toString("yyyyMMddhhmmss"));
				query.bindValue(":rights", list[i]->getRights());
				query.bindValue(":last_change", list[i]->getModifiedDate().toString("yyyyMMddhhmmss"));
				query.exec();

				// inserting line with JPEG
				if(type == File::JPEG && list[i]->additionalImageInfo()) {
					query.prepare("INSERT INTO pictures (id, width, height, depth, thumbnail, exif) VALUES (:id, :width, :height, :depth, :thumbnail, :exif)");
					query.bindValue(":id", parent);
					query.bindValue(":width", list[i]->getPicture()->getWidth());
					query.bindValue(":height", list[i]->getPicture()->getHeight());
					query.bindValue(":depth", 16);
					query.bindValue(":thumbnail", list[i]->getPicture()->getThumbnail());
					query.bindValue(":exif", list[i]->getPicture()->getExif());
					query.exec();
				}
				// audio file
				if(type == File::AudioContent && list[i]->additionalAudioInfo()) {
					Audio *audio = list[i]->getAudio();
					query.prepare("INSERT INTO audio (id, length, version, layer, bitrate, freq, channel, tag_title, tag_artist, tag_composer, tag_orig_artist, tag_album, tag_genre, tag_year, tag_track, tag_comment, tag_encoder) VALUES (:id, :length, :version, :layer, :bitrate, :freq, :channel, :tag_title, :tag_artist, :tag_composer, :tag_orig_artist, :tag_album, :tag_genre, :tag_year, :tag_track, :tag_comment, :tag_encoder)");
					query.bindValue(":id", parent);
					query.bindValue(":length", audio->getLength());
					query.bindValue(":version", audio->getVersion());
					query.bindValue(":layer", audio->getLayer());
					query.bindValue(":bitrate", audio->getBitrate());
					query.bindValue(":freq", audio->getFreq());
					query.bindValue(":channel", audio->getChannel());
					query.bindValue(":tag_title", audio->getTag_title());
					query.bindValue(":tag_artist", audio->getTag_artist());
					query.bindValue(":tag_composer", audio->getTag_composer());
					query.bindValue(":tag_orig_artist", audio->getTag_orig_artist());
					query.bindValue(":tag_album", audio->getTag_album());
					query.bindValue(":tag_genre", audio->getTag_genre());
					query.bindValue(":tag_year", audio->getTag_year());
					query.bindValue(":tag_track", audio->getTag_track());
					query.bindValue(":tag_comment", audio->getTag_comment());
					query.bindValue(":tag_encoder", audio->getTag_encoder());
					query.exec();
				}
				// txt file
				if(type == File::Text && list[i]->getContent()->size() > 0) {
					query.prepare("INSERT INTO documents (id, content, all_content) VALUES (:id, :content, :all_content)");
					query.bindValue(":id", parent);
					query.bindValue(":content", QString(*list[i]->getContent()));
					query.bindValue(":all_content", list[i]->isAllContent());
					query.exec();
					qDebug() << db.lastError().text() << list[i]->getContent();
				}
				// pdf file (document)
				if(type == File::PDF && list[i]->additionalDocumentInfo()) {
					Document *doc = list[i]->getDocument();
					query.prepare("INSERT INTO documents (id, content, all_content, author, title, subject, creator, keywords, pages) VALUES (:id, :content, :all_content, :author, :title, :subject, :creator, :keywords, :pages)");
					query.bindValue(":id", parent);
					query.bindValue(":content", QString(*list[i]->getContent()));
					query.bindValue(":all_content", list[i]->isAllContent());
					query.bindValue(":author", doc->getAuthor());
					query.bindValue(":title", doc->getTitle());
					query.bindValue(":subject", doc->getSubject());
					query.bindValue(":creator", doc->getCreator());
					query.bindValue(":keywords", doc->getKeywords());
					query.bindValue(":pages", doc->getPages());
					query.exec();
					qDebug() << db.lastError().text() << list[i]->getContent();
				}
			}
			insertFileListToSql(list[i]->children, 0, parent, db);
		}
	}
}

void ScanDialog::accept()
{
	this->close();
	((MainWindow *)mw)->updateTreeView();
}

void ScanDialog::reject()
{
	this->done(0.);
	
}

void ScanDialog::processFilterJPEG(QString filename, File *file)
{
	int SIZE = prefs->thumbnail_size;
	
	QByteArray array = filename.toUtf8();
	const char *filepath = array.constData();
	
	cimg_library::CImg<unsigned char> image(filepath);
	int dimx = image.dimx(),	dimy = image.dimy();

	file->getPicture()->setWidth(dimx);
	file->getPicture()->setHeight(dimy);
	double rate = (double)dimx/dimy;
	// shrinking to the right size at good rate
	if(dimx>SIZE | dimy>SIZE) {
		int dim;
		if(rate>1.0) {
			dim = (int)(SIZE/rate);
			image.resize(SIZE, dim);
			dimx = SIZE;
			dimy = dim;
		}
		else {
			dim = (int)(SIZE*rate);
			image.resize(dim, SIZE);
			dimx = dim;
			dimy = SIZE;
		}
	}
	//qDebug() << "souradnice " << dimx << " " << dimy;
	
	if(prefs->thumbnail) {
		// conversion CImg to QByteArray
		QImage *dest = new QImage(dimx, dimy, QImage::Format_RGB32);
		
		for(int y=0; y<dimy; y++) {
			for(int x=0; x<dimx; x++) {
				const unsigned char 
				r = (unsigned char)image(x,y,0),
				g = (unsigned char)image(x,y,1),
				b = (unsigned char)image(x,y,2);
				dest->setPixel(x,y,qRgb(r,g,b));
			}
		}
	
		//qDebug() << "processing " << iter.filePath() << dest;
	
		QByteArray ba;
		QBuffer buffer(&ba);
		buffer.open(QIODevice::WriteOnly);
		dest->save(&buffer, "JPG");
		
		// save to File	
		//currentFolder->at(index)->setThumbnail(ba);
		file->getPicture()->setThumbnail(ba);
	}
	if(prefs->exif) {
		//qDebug() << "exif begins " << filepath;
		QString exif = "-1";
		try {
			Exiv2::Image::AutoPtr img = Exiv2::ImageFactory::open(filepath);
			img->readMetadata();
			
			Exiv2::ExifData &exifData = img->exifData();
			if (exifData.empty()) {
				exif = "0";
				//throw Exiv2::Error(1, error);
			}
			else {
				exif = "";
	
				Exiv2::ExifData::const_iterator i = exifData.begin();
				for(int j = 0; j < Picture::exifKeys.size(); j+=2) {
					i = exifData.findKey(Exiv2::ExifKey(Picture::exifKeys.at(j).toStdString()));
					if(i != exifData.end())
						exif += QString::fromStdString(i->toString());
					exif += ";";
				}
			}
		}
		catch (Exiv2::AnyError& e) {
			std::cout << "Caught Exiv2 exception '" << e << "'\n";
			// doing nothing, just exif will be empty
			exif = "-1";
		}
		//qDebug() << "exif ends " << iter.filePath().toUtf8().data();
		file->getPicture()->setExif(exif);
	}
	else {
		file->getPicture()->setExif("0");
	}
}

void ScanDialog::processFilterMp3(QString filename, File *file)
{
	qDebug() << "processing mp3 file: " << filename;

	Audio *audio = file->getAudio();

	QByteArray array = filename.toUtf8();
	const char *filepath = array.constData();

	QTextCodec *codec = QTextCodec::codecForName(prefs->tag_charset.toUtf8());

	ID3_Tag myTag(filepath);
	ID3_Frame* myFrame = myTag.Find(ID3FID_ALBUM);
	if (NULL != myFrame) {
		const char* album = myFrame->GetField(ID3FN_TEXT)->GetRawText();
		QByteArray encodedString(album);
		audio->setTag_album(codec->toUnicode(encodedString));
		//qDebug() << "Album: " << album;
	}
	myFrame = myTag.Find(ID3FID_TITLE);
	if (NULL != myFrame) {
		const char* title = myFrame->GetField(ID3FN_TEXT)->GetRawText();
		QByteArray encodedString(title);
		audio->setTag_title(codec->toUnicode(encodedString));
		//qDebug() << "Title: " << title;
	}
	myFrame = myTag.Find(ID3FID_LEADARTIST);
	if (NULL != myFrame) {
		const char* artist = myFrame->GetField(ID3FN_TEXT)->GetRawText();
		QByteArray encodedString(artist);
		audio->setTag_artist(codec->toUnicode(encodedString));
		//qDebug() << "Artist: " << artist;
	}
	myFrame = myTag.Find(ID3FID_ORIGARTIST);
	if (NULL != myFrame) {
		const char* origartist = myFrame->GetField(ID3FN_TEXT)->GetRawText();
		QByteArray encodedString(origartist);
		audio->setTag_orig_artist(codec->toUnicode(encodedString));
		//qDebug() << "Original artist: " << origartist;
	}
	myFrame = myTag.Find(ID3FID_TRACKNUM);
	if (NULL != myFrame) {
		const char* track = myFrame->GetField(ID3FN_TEXT)->GetRawText();
		QByteArray encodedString(track);
		audio->setTag_track(codec->toUnicode(encodedString));
		//qDebug() << "Track no.: " << track;
	}
	myFrame = myTag.Find(ID3FID_YEAR);
	if (NULL != myFrame) {
		const char* year = myFrame->GetField(ID3FN_TEXT)->GetRawText();
		QByteArray encodedString(year);
		audio->setTag_year(codec->toUnicode(encodedString));
		//qDebug() << "Year: " << year;
	}
	myFrame = myTag.Find(ID3FID_COMMENT);
	if (NULL != myFrame) {
		const char* comment = myFrame->GetField(ID3FN_TEXT)->GetRawText();
		QByteArray encodedString(comment);
		audio->setTag_comment(codec->toUnicode(encodedString));
		//qDebug() << "Comment: " << comment;
	}
	myFrame = myTag.Find(ID3FID_CONTENTTYPE);
	if (NULL != myFrame) {
		const char* genre = myFrame->GetField(ID3FN_TEXT)->GetRawText();
		QByteArray encodedString(genre);
		audio->setTag_genre(codec->toUnicode(encodedString));
		//qDebug() << "Genre: " << genre;
	}
	myFrame = myTag.Find(ID3FID_ENCODERSETTINGS);
	if (NULL != myFrame) {
		const char* encoder = myFrame->GetField(ID3FN_TEXT)->GetRawText();
		QByteArray encodedString(encoder);
		audio->setTag_encoder(codec->toUnicode(encodedString));
		//qDebug() << "Encoder: " << encoder;
	}
	myFrame = myTag.Find(ID3FID_COMPOSER);
	if (NULL != myFrame) {
		const char* composer = myFrame->GetField(ID3FN_TEXT)->GetRawText();
		QByteArray encodedString(composer);
		audio->setTag_composer(codec->toUnicode(encodedString));
		//qDebug() << "Composer: " << composer;
	}
	
	// end of id3 tag processing


/*
	// mp3 header diggin
	FILE *fp;
	
	int curch;
		
	int flag1=0;
	QString fileinfo;

	fp=fopen(filepath,"rb");
	
	fileinfo = "Filename : " + QString(filepath) + "\n";

#ifndef O_BINARY
#define O_BINARY 0
#endif

	// filesize.....	
	int handle = open(filepath, O_BINARY);
	int filesize; // = filelength(handle);
	struct stat status;
	if (stat(filepath, &status)==-1) filesize = 0;
	filesize = status.st_size;
	fileinfo += "Size (in bytes) : " + QString::number(filesize) + "\n";

	// finding first frame for MPEG 1 LAYER III
	do
	{
		curch=fgetc(fp);
		if(curch==255)
		{
			curch=fgetc(fp);
			if(tolower(curch/16)==15) flag1=1;
		}
	} while(flag1==0);

	// position of first frame header......
	fpos_t filepos;
	char firstframeposition[10];

	fgetpos(fp,&filepos);
	//filepos = filepos - 2;
//	fsetpos (fp,&filepos-2);
//	char c = fgetc (fp);

//	int firstheaderpos = (int)&filepos-2;
	//_ltoa(firstheaderpos,firstframeposition,10);
//	fileinfo += "First frame found at byte :" + QString(c) + "\n";//firstframeposition;

	// version check MPEG 1/2...
	qDebug() << "curch1: " << curch;
	int impegversion = tolower(((curch%16)/4)/2);
	if(impegversion==1) fileinfo += "MPEG 1 \n";
	if(impegversion==0) fileinfo="MPEG 2 \n";


    // layer check....
	int layer=tolower((((curch%16)/4)%2)*2+(((curch%16)%4)/2));
	QString mpeglayer[4]={"Reserved","Layer III","Layer II","Layer I"};
	fileinfo += mpeglayer[layer] + "\n";

	//if(layer!=1) return 1;

	//get next byte to read 3rd byte of header. 
	curch=fgetc(fp);
	qDebug() << "curch2: " << curch;

	// bitrate info
	int bitratetable[2][16]={0,8,16,24,32,64,80,56,64,128,160,112,128,256,320,0,0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0};
	int mp3bitrate=bitratetable[impegversion][tolower(curch/16)];  
	fileinfo += "Bitrate (kbps) : " + QString::number(mp3bitrate) + "\n";

	// frequency info
	long int frequencytable[2][4]={22050,24000,16000,0,44100,48000,32000,0};
	int mp3frequency=frequencytable[impegversion][tolower((curch%16)/4)];
	fileinfo += "Frequency (Hz) : " + QString::number(mp3frequency) + "\n";

	// get next char to read 4th byte of header.
	curch=fgetc(fp);

	//channel mode
	QString channelmode[4]={"Stereo","Joint Stereo","Dual Channel","Single Channel"};
	int ichannelmode = tolower((curch/16)/4);
	fileinfo += channelmode[ichannelmode] + "\n";

	qDebug() << fileinfo;
*/
	char c;
	unsigned char d;
	int flag = 0;
	QString fileinfo;
	int firstheaderpos = 0;

	QFile mp3file(filename);
	mp3file.open(QIODevice::ReadOnly);
	if(mp3file.isOpen()) {
		while(mp3file.getChar(&c) && flag == 0) {
			d = (unsigned char) c;
			if(d == 255) {
				mp3file.getChar(&c);
				d = (unsigned char) c;
				//qDebug() << "curch1: " << d;
				if(tolower(d/16)==15) {
					qDebug() << "first frame header found";
					firstheaderpos = mp3file.pos();
					flag = 1;
				}
			}
		}
	}
	else {
		qDebug() << "mp3 couldn't be opened!!!";
	}

	//qDebug() << "curch1: " << d;
	int impegversion = tolower(((d%16)/4)/2);
	if(impegversion==1) {
		fileinfo = "MPEG 1 \n";
		audio->setVersion("MPEG 1");
	}
	if(impegversion==0) {
		fileinfo ="MPEG 2 \n";
		audio->setVersion("MPEG 2");
	}

    // layer check....
	int layer=tolower((((d%16)/4)%2)*2+(((d%16)%4)/2));
	QString mpeglayer[4]={"Reserved","Layer III","Layer II","Layer I"};
	fileinfo += mpeglayer[layer] + "\n";
	audio->setLayer(mpeglayer[layer]);

	//get next byte to read 3rd byte of header. 
	mp3file.ungetChar(c);
	mp3file.getChar(&c);
	d = (unsigned char) c;
	//qDebug() << "curch2: " << d;

	// bitrate info
	int bitratetable[2][16]={0,8,16,24,32,64,80,56,64,128,160,112,128,256,320,0,0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0};
	int mp3bitrate=bitratetable[impegversion][tolower(d/16)];  
	fileinfo += "Bitrate (kbps) : " + QString::number(mp3bitrate) + "\n";
	audio->setBitrate(mp3bitrate);

	// frequency info
	long int frequencytable[2][4]={22050,24000,16000,0,44100,48000,32000,0};
	int mp3frequency=frequencytable[impegversion][tolower((d%16)/4)];
	fileinfo += "Frequency (Hz) : " + QString::number(mp3frequency) + "\n";
	audio->setFreq(mp3frequency);

	// padding bit
	int paddingbit=tolower(((d%16)%4)/2);
	if(paddingbit==0) fileinfo += "Padding : No";
	else fileinfo += "Padding : Yes";

	// get next char to read 4th byte of header.
	mp3file.getChar(&c);
	d = (unsigned char) c;
	//qDebug() << "curch3: " << d;

	//channel mode
	QString channelmode[4]={"Stereo","Joint Stereo","Dual Channel","Single Channel"};	// it is connected to Audio::channelsToString()
	int ichannelmode = tolower((d/16)/4);
	fileinfo += channelmode[ichannelmode] + "\n";
	audio->setChannel(ichannelmode);

	// frame size
	int framesize=(144000*mp3bitrate/mp3frequency)+paddingbit;
	fileinfo += "Framesize : " + QString::number(framesize) + "\n";

	// frame number
	int frames=(mp3file.size()-firstheaderpos)/framesize;
	fileinfo += "Frames : " + QString::number(frames) + "\n";

	// length in seconds
	int playtime = toupper(frames*26/1000);
	fileinfo += "Length (in sec) : " + QString::number(playtime) + "\n";
	audio->setLength(playtime);

	//qDebug() << fileinfo;
	mp3file.close();
}

void ScanDialog::processFilterTxt(QString filename, File *file, QString suffix)
{
	qDebug() << "processing txt (nfo) file: " << filename;

	int maxsize;
	bool all_content = true;
	if(suffix == "nfo") {
		maxsize = 15000;
	}
	else {
		// suffix == txt
		maxsize = 1024;
	}

	QFile textfile(filename);
	if (!textfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
		qDebug() << "problem while reading text file";
		return;
	}	

	QByteArray *content = new QByteArray();
	while (!textfile.atEnd()) {
			QByteArray line = textfile.readLine(maxsize);
			//qDebug() << line;
			content->append(line);
			if(content->size() > maxsize) {
				all_content = false;
				break;
			}
	}
	file->setContent(content);
	file->setAllContent(all_content);
	qDebug() << "content set to: " << QString(*content) << file->getContent()->size();
}

void ScanDialog::processFilterPdf(QString filename, File *file)
{
	qDebug() << "processing pdf file: " << filename;
	
	Poppler::Document* document = Poppler::Document::load(filename);
	if (!document || document->isLocked()) {
		qDebug() << "pdf file cannot be accessed";
		delete document;
		return;
	}
	
	Poppler::Page* pdfPage = document->page(0);  // Document starts at page 0
	if (pdfPage == 0) {
		qDebug() << "first page of pdf file is not accessible";
		return;
	}

	QRectF rect;
	//qDebug() << document->info("Title") << document->info("Subject") << document->info("Author") << document->info("Keywords") << document->info("Creator") << document->infoKeys() << pdfPage->text(rect);
	qDebug() << "pdf1";
	Document *doc = file->getDocument();
	qDebug() << "pdf1a" << document->infoKeys();
	doc->setAuthor(document->info("Author"));
	qDebug() << "pdf1b";
	doc->setTitle(document->info("Title"));
	doc->setSubject(document->info("Subject"));
	doc->setKeywords(document->info("Keywords"));
	doc->setCreator(document->info("Creator"));
	qDebug() << "pdf1c";
	doc->setPages(document->numPages());
	qDebug() << "pdf2";
	if(pdfPage->text(rect).length() > 0) {
		QByteArray *text = new QByteArray(pdfPage->text(rect).toUtf8());
		file->setContent(text);
		file->setAllContent(false);
	}
	qDebug() << "pdf3";
	delete pdfPage;
	delete document;
	qDebug() << "end of processing pdf file";
}

